/**
 * create by zhangpu
 * date:2015年3月12日
 */
package com.acooly.module.openapi.client.provider.cj.marshall;

import com.acooly.core.utils.Reflections;
import com.acooly.core.utils.Strings;
import com.acooly.module.openapi.client.api.anotation.ApiItem;
import com.acooly.module.openapi.client.api.exception.ApiClientException;
import com.acooly.module.openapi.client.api.marshal.ApiUnmarshal;
import com.acooly.module.openapi.client.api.message.MessageFactory;
import com.acooly.module.openapi.client.provider.cj.CjConstants;
import com.acooly.module.openapi.client.provider.cj.domain.CjResponse;
import com.acooly.module.openapi.client.provider.cj.enums.CjServiceEnum;
import com.acooly.module.openapi.client.provider.cj.partner.CjPartnerIdLoadManager;
import com.acooly.module.openapi.client.provider.cj.utils.CjSignHelper;
import com.acooly.module.openapi.client.provider.cj.utils.XmlHelper;
import com.acooly.module.safety.key.KeyLoadManager;
import com.acooly.module.safety.support.KeyStoreInfo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;


/**
 * @author zhangpu
 */
@Slf4j
@Service
public class CjResponseUnmarshall extends CjMarshallSupport implements ApiUnmarshal<CjResponse, String> {

    private static final Logger logger = LoggerFactory.getLogger(CjResponseUnmarshall.class);

    @Resource(name = "cjMessageFactory")
    private MessageFactory messageFactory;

    @Resource(name = "cjPartnerIdLoadManager")
    private CjPartnerIdLoadManager partnerIdLoadManager;

    @Autowired
    private KeyLoadManager keyStoreLoadManager;

    @SuppressWarnings("unchecked")
    @Override
    public CjResponse unmarshal(String message, String serviceName) {
        try {
            logger.info("响应报文:{}", message);
            CjResponse cjResponse = (CjResponse) messageFactory.getResponse (serviceName);
            //解析报文
            doUnmarshall(message,cjResponse,serviceName);
            String parnerId = partnerIdLoadManager.load(cjResponse);
            KeyStoreInfo keyStoreInfo = keyStoreLoadManager.load(parnerId, CjConstants.PROVIDER_NAME);
            doVerifySign(message,keyStoreInfo);
            return cjResponse;
        } catch (Exception e) {
            throw new ApiClientException("解析响应报文错误:" + e.getMessage());
        }
    }

    protected CjResponse doUnmarshall(String message, CjResponse response, String serviceName) throws Exception {

        Map<String, Object> messageMap = new HashMap<String, Object>();

        //解析返回的报文
        if(Strings.equals(CjServiceEnum.CJ_REAL_DEDUCT.code(),serviceName)){
            XmlHelper.parseCjRealMsgToDto(message,messageMap);
            response.setServiceCode(CjServiceEnum.CJ_REAL_DEDUCT.code());
        }else if(Strings.equals(CjServiceEnum.CJ_REAL_DEDUCT_QUERY.code(),serviceName)){
            XmlHelper.parseRealQueryMsgToDto(message,messageMap);
            response.setServiceCode(CjServiceEnum.CJ_REAL_DEDUCT_QUERY.code());
        }else if(Strings.equals(CjServiceEnum.CJ_BATCH_DEDUCT.code(),serviceName)){
            XmlHelper.parseCjBatchMsgToDto(message,messageMap);
        }else if(Strings.equals(CjServiceEnum.CJ_BATCH_DEDUCT_QUERY.code(),serviceName)){
            XmlHelper.parseBatchQueryMsgToDto(message,messageMap);
            response.setServiceCode(CjServiceEnum.CJ_BATCH_DEDUCT_QUERY.code());
        }

        Set<Field> fields = Reflections.getFields(response.getClass());
        String key = null;
        for (Field field : fields) {
            ApiItem apiItem = field.getAnnotation(ApiItem.class);
            if (apiItem != null && Strings.isNotBlank(apiItem.value())) {
                key = apiItem.value();
            }else {
                key = field.getName();
            }
            Reflections.invokeSetter(response, field.getName(), messageMap.get(key));
        }
        return response;
    }

    protected void doVerifySign(String message,KeyStoreInfo keyStoreInfo) throws Exception{
        CjSignHelper singHelper = new CjSignHelper(keyStoreInfo);
        if(!singHelper.verifyCjServerXml(message).result){//验签
            throw new ApiClientException("验签失败！");
        }
    }
}
